home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / perl / sprite / doio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-14  |  59.1 KB  |  2,842 lines

  1. /* $RCSfile: doio.c,v $$Revision: 1.3 $$Date: 91/11/14 12:52:09 $
  2.  *
  3.  *    Copyright (c) 1991, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of either the GNU General Public
  6.  *    License or the Artistic License, as specified in the README file.
  7.  *
  8.  * $Log:    doio.c,v $
  9.  * Revision 1.3  91/11/14  12:52:09  jhh
  10.  * patchlevel 19
  11.  * 
  12.  * Revision 4.0.1.4  91/11/05  16:51:43  lwall
  13.  * patch11: prepared for ctype implementations that don't define isascii()
  14.  * patch11: perl mistook some streams for sockets because they return mode 0 too
  15.  * patch11: reopening STDIN, STDOUT and STDERR failed on some machines
  16.  * patch11: certain perl errors should set EBADF so that $! looks better
  17.  * patch11: truncate on a closed filehandle could dump
  18.  * patch11: stats of _ forgot whether prior stat was actually lstat
  19.  * patch11: -T returned true on NFS directory
  20.  *
  21.  * Revision 1.2  91/08/12  16:41:16  jhh
  22.  * Sprite version of stat() returns a few extra fields
  23.  * 
  24.  * Revision 4.0.1.3  91/06/10  01:21:19  lwall
  25.  * patch10: read didn't work from character special files open for writing
  26.  * patch10: close-on-exec wrongly set on system file descriptors
  27.  * 
  28.  * Revision 4.0.1.2  91/06/07  10:53:39  lwall
  29.  * patch4: new copyright notice
  30.  * patch4: system fd's are now treated specially
  31.  * patch4: added $^F variable to specify maximum system fd, default 2
  32.  * patch4: character special files now opened with bidirectional stdio buffers
  33.  * patch4: taintchecks could improperly modify parent in vfork()
  34.  * patch4: many, many itty-bitty portability fixes
  35.  * 
  36.  * Revision 4.0.1.1  91/04/11  17:41:06  lwall
  37.  * patch1: hopefully straightened out some of the Xenix mess
  38.  * 
  39.  * Revision 4.0  91/03/20  01:07:06  lwall
  40.  * 4.0 baseline.
  41.  * 
  42.  */
  43.  
  44. #include "EXTERN.h"
  45. #include "perl.h"
  46.  
  47. #ifdef HAS_SOCKET
  48. #include <sys/socket.h>
  49. #include <netdb.h>
  50. #endif
  51.  
  52. #ifdef HAS_SELECT
  53. #ifdef I_SYS_SELECT
  54. #ifndef I_SYS_TIME
  55. #include <sys/select.h>
  56. #endif
  57. #endif
  58. #endif
  59.  
  60. #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
  61. #include <sys/ipc.h>
  62. #ifdef HAS_MSG
  63. #include <sys/msg.h>
  64. #endif
  65. #ifdef HAS_SEM
  66. #include <sys/sem.h>
  67. #endif
  68. #ifdef HAS_SHM
  69. #include <sys/shm.h>
  70. #endif
  71. #endif
  72.  
  73. #ifdef I_PWD
  74. #include <pwd.h>
  75. #endif
  76. #ifdef I_GRP
  77. #include <grp.h>
  78. #endif
  79. #ifdef I_UTIME
  80. #include <utime.h>
  81. #endif
  82. #ifdef I_FCNTL
  83. #include <fcntl.h>
  84. #endif
  85. #ifdef I_SYS_FILE
  86. #include <sys/file.h>
  87. #endif
  88.  
  89. int laststatval = -1;
  90. int laststype = O_STAT;
  91.  
  92. bool
  93. do_open(stab,name,len)
  94. STAB *stab;
  95. register char *name;
  96. int len;
  97. {
  98.     FILE *fp;
  99.     register STIO *stio = stab_io(stab);
  100.     char *myname = savestr(name);
  101.     int result;
  102.     int fd;
  103.     int writing = 0;
  104.     char mode[3];        /* stdio file mode ("r\0" or "r+\0") */
  105.     FILE *saveifp = Nullfp;
  106.     FILE *saveofp = Nullfp;
  107.     char savetype = ' ';
  108.  
  109.     name = myname;
  110.     forkprocess = 1;        /* assume true if no fork */
  111.     while (len && isSPACE(name[len-1]))
  112.     name[--len] = '\0';
  113.     if (!stio)
  114.     stio = stab_io(stab) = stio_new();
  115.     else if (stio->ifp) {
  116.     fd = fileno(stio->ifp);
  117.     if (stio->type == '-')
  118.         result = 0;
  119.     else if (fd <= maxsysfd) {
  120.         saveifp = stio->ifp;
  121.         saveofp = stio->ofp;
  122.         savetype = stio->type;
  123.         result = 0;
  124.     }
  125.     else if (stio->type == '|')
  126.         result = mypclose(stio->ifp);
  127.     else if (stio->ifp != stio->ofp) {
  128.         if (stio->ofp) {
  129.         result = fclose(stio->ofp);
  130.         fclose(stio->ifp);    /* clear stdio, fd already closed */
  131.         }
  132.         else
  133.         result = fclose(stio->ifp);
  134.     }
  135.     else
  136.         result = fclose(stio->ifp);
  137.     if (result == EOF && fd > maxsysfd)
  138.         fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
  139.           stab_name(stab));
  140.     stio->ofp = stio->ifp = Nullfp;
  141.     }
  142.     if (*name == '+' && len > 1 && name[len-1] != '|') {    /* scary */
  143.     mode[1] = *name++;
  144.     mode[2] = '\0';
  145.     --len;
  146.     writing = 1;
  147.     }
  148.     else  {
  149.     mode[1] = '\0';
  150.     }
  151.     stio->type = *name;
  152.     if (*name == '|') {
  153.     /*SUPPRESS 530*/
  154.     for (name++; isSPACE(*name); name++) ;
  155. #ifdef TAINT
  156.     taintenv();
  157.     taintproper("Insecure dependency in piped open");
  158. #endif
  159.     fp = mypopen(name,"w");
  160.     writing = 1;
  161.     }
  162.     else if (*name == '>') {
  163. #ifdef TAINT
  164.     taintproper("Insecure dependency in open");
  165. #endif
  166.     name++;
  167.     if (*name == '>') {
  168.         mode[0] = stio->type = 'a';
  169.         name++;
  170.     }
  171.     else
  172.         mode[0] = 'w';
  173.     writing = 1;
  174.     if (*name == '&') {
  175.       duplicity:
  176.         name++;
  177.         while (isSPACE(*name))
  178.         name++;
  179.         if (isDIGIT(*name))
  180.         fd = atoi(name);
  181.         else {
  182.         stab = stabent(name,FALSE);
  183.         if (!stab || !stab_io(stab)) {
  184. #ifdef EINVAL
  185.             errno = EINVAL;
  186. #endif
  187.             goto say_false;
  188.         }
  189.         if (stab_io(stab) && stab_io(stab)->ifp) {
  190.             fd = fileno(stab_io(stab)->ifp);
  191.             if (stab_io(stab)->type == 's')
  192.             stio->type = 's';
  193.         }
  194.         else
  195.             fd = -1;
  196.         }
  197.         if (!(fp = fdopen(fd = dup(fd),mode))) {
  198.         close(fd);
  199.         }
  200.     }
  201.     else {
  202.         while (isSPACE(*name))
  203.         name++;
  204.         if (strEQ(name,"-")) {
  205.         fp = stdout;
  206.         stio->type = '-';
  207.         }
  208.         else  {
  209.         fp = fopen(name,mode);
  210.         }
  211.     }
  212.     }
  213.     else {
  214.     if (*name == '<') {
  215.         mode[0] = 'r';
  216.         name++;
  217.         while (isSPACE(*name))
  218.         name++;
  219.         if (*name == '&')
  220.         goto duplicity;
  221.         if (strEQ(name,"-")) {
  222.         fp = stdin;
  223.         stio->type = '-';
  224.         }
  225.         else
  226.         fp = fopen(name,mode);
  227.     }
  228.     else if (name[len-1] == '|') {
  229. #ifdef TAINT
  230.         taintenv();
  231.         taintproper("Insecure dependency in piped open");
  232. #endif
  233.         name[--len] = '\0';
  234.         while (len && isSPACE(name[len-1]))
  235.         name[--len] = '\0';
  236.         /*SUPPRESS 530*/
  237.         for (; isSPACE(*name); name++) ;
  238.         fp = mypopen(name,"r");
  239.         stio->type = '|';
  240.     }
  241.     else {
  242.         stio->type = '<';
  243.         /*SUPPRESS 530*/
  244.         for (; isSPACE(*name); name++) ;
  245.         if (strEQ(name,"-")) {
  246.         fp = stdin;
  247.         stio->type = '-';
  248.         }
  249.         else
  250.         fp = fopen(name,"r");
  251.     }
  252.     }
  253.     Safefree(myname);
  254.     if (!fp)
  255.     goto say_false;
  256.     if (stio->type &&
  257.       stio->type != '|' && stio->type != '-') {
  258.     if (fstat(fileno(fp),&statbuf) < 0) {
  259.         (void)fclose(fp);
  260.         goto say_false;
  261.     }
  262.     if (S_ISSOCK(statbuf.st_mode))
  263.         stio->type = 's';    /* in case a socket was passed in to us */
  264. #ifdef HAS_SOCKET
  265.     else if (
  266. #ifdef S_IFMT
  267.         !(statbuf.st_mode & S_IFMT)
  268. #else
  269.         !statbuf.st_mode
  270. #endif
  271.     ) {
  272.         if (getsockname(fileno(fp), tokenbuf, 0) >= 0 || errno != ENOTSOCK)
  273.         stio->type = 's'; /* some OS's return 0 on fstat()ed socket */
  274.                 /* but some return 0 for streams too, sigh */
  275.     }
  276. #endif
  277.     }
  278.     if (saveifp) {        /* must use old fp? */
  279.     fd = fileno(saveifp);
  280.     if (saveofp) {
  281.         fflush(saveofp);        /* emulate fclose() */
  282.         if (saveofp != saveifp) {    /* was a socket? */
  283.         fclose(saveofp);
  284.         if (fd > 2)
  285.             Safefree(saveofp);
  286.         }
  287.     }
  288.     if (fd != fileno(fp)) {
  289.         dup2(fileno(fp), fd);
  290.         fclose(fp);
  291.     }
  292.     fp = saveifp;
  293.     }
  294. #if defined(HAS_FCNTL) && defined(F_SETFD)
  295.     fd = fileno(fp);
  296.     fcntl(fd,F_SETFD,fd > maxsysfd);
  297. #endif
  298.     stio->ifp = fp;
  299.     if (writing) {
  300.     if (stio->type == 's'
  301.       || (stio->type == '>' && S_ISCHR(statbuf.st_mode)) ) {
  302.         if (!(stio->ofp = fdopen(fileno(fp),"w"))) {
  303.         fclose(fp);
  304.         stio->ifp = Nullfp;
  305.         goto say_false;
  306.         }
  307.     }
  308.     else
  309.         stio->ofp = fp;
  310.     }
  311.     return TRUE;
  312.  
  313. say_false:
  314.     stio->ifp = saveifp;
  315.     stio->ofp = saveofp;
  316.     stio->type = savetype;
  317.     return FALSE;
  318. }
  319.  
  320. FILE *
  321. nextargv(stab)
  322. register STAB *stab;
  323. {
  324.     register STR *str;
  325. #ifndef FLEXFILENAMES
  326.     int filedev;
  327.     int fileino;
  328. #endif
  329.     int fileuid;
  330.     int filegid;
  331.     static int filemode = 0;
  332.     static int lastfd;
  333.     static char *oldname;
  334.  
  335.     if (!argvoutstab)
  336.     argvoutstab = stabent("ARGVOUT",TRUE);
  337.     if (filemode & (S_ISUID|S_ISGID)) {
  338.     fflush(stab_io(argvoutstab)->ifp);  /* chmod must follow last write */
  339. #ifdef HAS_FCHMOD
  340.     (void)fchmod(lastfd,filemode);
  341. #else
  342.     (void)chmod(oldname,filemode);
  343. #endif
  344.     }
  345.     filemode = 0;
  346.     while (alen(stab_xarray(stab)) >= 0) {
  347.     str = ashift(stab_xarray(stab));
  348.     str_sset(stab_val(stab),str);
  349.     STABSET(stab_val(stab));
  350.     oldname = str_get(stab_val(stab));
  351.     if (do_open(stab,oldname,stab_val(stab)->str_cur)) {
  352.         if (inplace) {
  353. #ifdef TAINT
  354.         taintproper("Insecure dependency in inplace open");
  355. #endif
  356.         if (strEQ(oldname,"-")) {
  357.             str_free(str);
  358.             defoutstab = stabent("STDOUT",TRUE);
  359.             return stab_io(stab)->ifp;
  360.         }
  361. #ifndef FLEXFILENAMES
  362.         filedev = statbuf.st_dev;
  363.         fileino = statbuf.st_ino;
  364. #endif
  365.         filemode = statbuf.st_mode;
  366.         fileuid = statbuf.st_uid;
  367.         filegid = statbuf.st_gid;
  368.         if (!S_ISREG(filemode)) {
  369.             warn("Can't do inplace edit: %s is not a regular file",
  370.               oldname );
  371.             do_close(stab,FALSE);
  372.             str_free(str);
  373.             continue;
  374.         }
  375.         if (*inplace) {
  376. #ifdef SUFFIX
  377.             add_suffix(str,inplace);
  378. #else
  379.             str_cat(str,inplace);
  380. #endif
  381. #ifndef FLEXFILENAMES
  382.             if (stat(str->str_ptr,&statbuf) >= 0
  383.               && statbuf.st_dev == filedev
  384.               && statbuf.st_ino == fileino ) {
  385.             warn("Can't do inplace edit: %s > 14 characters",
  386.               str->str_ptr );
  387.             do_close(stab,FALSE);
  388.             str_free(str);
  389.             continue;
  390.             }
  391. #endif
  392. #ifdef HAS_RENAME
  393. #ifndef MSDOS
  394.             if (rename(oldname,str->str_ptr) < 0) {
  395.             warn("Can't rename %s to %s: %s, skipping file",
  396.               oldname, str->str_ptr, strerror(errno) );
  397.             do_close(stab,FALSE);
  398.             str_free(str);
  399.             continue;
  400.             }
  401. #else
  402.             do_close(stab,FALSE);
  403.             (void)unlink(str->str_ptr);
  404.             (void)rename(oldname,str->str_ptr);
  405.             do_open(stab,str->str_ptr,stab_val(stab)->str_cur);
  406. #endif /* MSDOS */
  407. #else
  408.             (void)UNLINK(str->str_ptr);
  409.             if (link(oldname,str->str_ptr) < 0) {
  410.             warn("Can't rename %s to %s: %s, skipping file",
  411.               oldname, str->str_ptr, strerror(errno) );
  412.             do_close(stab,FALSE);
  413.             str_free(str);
  414.             continue;
  415.             }
  416.             (void)UNLINK(oldname);
  417. #endif
  418.         }
  419.         else {
  420. #ifndef MSDOS
  421.             if (UNLINK(oldname) < 0) {
  422.             warn("Can't rename %s to %s: %s, skipping file",
  423.               oldname, str->str_ptr, strerror(errno) );
  424.             do_close(stab,FALSE);
  425.             str_free(str);
  426.             continue;
  427.             }
  428. #else
  429.             fatal("Can't do inplace edit without backup");
  430. #endif
  431.         }
  432.  
  433.         str_nset(str,">",1);
  434.         str_cat(str,oldname);
  435.         errno = 0;        /* in case sprintf set errno */
  436.         if (!do_open(argvoutstab,str->str_ptr,str->str_cur)) {
  437.             warn("Can't do inplace edit on %s: %s",
  438.               oldname, strerror(errno) );
  439.             do_close(stab,FALSE);
  440.             str_free(str);
  441.             continue;
  442.         }
  443.         defoutstab = argvoutstab;
  444.         lastfd = fileno(stab_io(argvoutstab)->ifp);
  445.         (void)fstat(lastfd,&statbuf);
  446. #ifdef HAS_FCHMOD
  447.         (void)fchmod(lastfd,filemode);
  448. #else
  449.         (void)chmod(oldname,filemode);
  450. #endif
  451.         if (fileuid != statbuf.st_uid || filegid != statbuf.st_gid) {
  452. #ifdef HAS_FCHOWN
  453.             (void)fchown(lastfd,fileuid,filegid);
  454. #else
  455. #ifdef HAS_CHOWN
  456.             (void)chown(oldname,fileuid,filegid);
  457. #endif
  458. #endif
  459.         }
  460.         }
  461.         str_free(str);
  462.         return stab_io(stab)->ifp;
  463.     }
  464.     else
  465.         fprintf(stderr,"Can't open %s: %s\n",str_get(str), strerror(errno));
  466.     str_free(str);
  467.     }
  468.     if (inplace) {
  469.     (void)do_close(argvoutstab,FALSE);
  470.     defoutstab = stabent("STDOUT",TRUE);
  471.     }
  472.     return Nullfp;
  473. }
  474.  
  475. #ifdef HAS_PIPE
  476. void
  477. do_pipe(str, rstab, wstab)
  478. STR *str;
  479. STAB *rstab;
  480. STAB *wstab;
  481. {
  482.     register STIO *rstio;
  483.     register STIO *wstio;
  484.     int fd[2];
  485.  
  486.     if (!rstab)
  487.     goto badexit;
  488.     if (!wstab)
  489.     goto badexit;
  490.  
  491.     rstio = stab_io(rstab);
  492.     wstio = stab_io(wstab);
  493.  
  494.     if (!rstio)
  495.     rstio = stab_io(rstab) = stio_new();
  496.     else if (rstio->ifp)
  497.     do_close(rstab,FALSE);
  498.     if (!wstio)
  499.     wstio = stab_io(wstab) = stio_new();
  500.     else if (wstio->ifp)
  501.     do_close(wstab,FALSE);
  502.  
  503.     if (pipe(fd) < 0)
  504.     goto badexit;
  505.     rstio->ifp = fdopen(fd[0], "r");
  506.     wstio->ofp = fdopen(fd[1], "w");
  507.     wstio->ifp = wstio->ofp;
  508.     rstio->type = '<';
  509.     wstio->type = '>';
  510.     if (!rstio->ifp || !wstio->ofp) {
  511.     if (rstio->ifp) fclose(rstio->ifp);
  512.     else close(fd[0]);
  513.     if (wstio->ofp) fclose(wstio->ofp);
  514.     else close(fd[1]);
  515.     goto badexit;
  516.     }
  517.  
  518.     str_sset(str,&str_yes);
  519.     return;
  520.  
  521. badexit:
  522.     str_sset(str,&str_undef);
  523.     return;
  524. }
  525. #endif
  526.  
  527. bool
  528. do_close(stab,explicit)
  529. STAB *stab;
  530. bool explicit;
  531. {
  532.     bool retval = FALSE;
  533.     register STIO *stio;
  534.     int status;
  535.  
  536.     if (!stab)
  537.     stab = argvstab;
  538.     if (!stab) {
  539.     errno = EBADF;
  540.     return FALSE;
  541.     }
  542.     stio = stab_io(stab);
  543.     if (!stio) {        /* never opened */
  544.     if (dowarn && explicit)
  545.         warn("Close on unopened file <%s>",stab_name(stab));
  546.     return FALSE;
  547.     }
  548.     if (stio->ifp) {
  549.     if (stio->type == '|') {
  550.         status = mypclose(stio->ifp);
  551.         retval = (status == 0);
  552.         statusvalue = (unsigned short)status & 0xffff;
  553.     }
  554.     else if (stio->type == '-')
  555.         retval = TRUE;
  556.     else {
  557.         if (stio->ofp && stio->ofp != stio->ifp) {        /* a socket */
  558.         retval = (fclose(stio->ofp) != EOF);
  559.         fclose(stio->ifp);    /* clear stdio, fd already closed */
  560.         }
  561.         else
  562.         retval = (fclose(stio->ifp) != EOF);
  563.     }
  564.     stio->ofp = stio->ifp = Nullfp;
  565.     }
  566.     if (explicit)
  567.     stio->lines = 0;
  568.     stio->type = ' ';
  569.     return retval;
  570. }
  571.  
  572. bool
  573. do_eof(stab)
  574. STAB *stab;
  575. {
  576.     register STIO *stio;
  577.     int ch;
  578.  
  579.     if (!stab) {            /* eof() */
  580.     if (argvstab)
  581.         stio = stab_io(argvstab);
  582.     else
  583.         return TRUE;
  584.     }
  585.     else
  586.     stio = stab_io(stab);
  587.  
  588.     if (!stio)
  589.     return TRUE;
  590.  
  591.     while (stio->ifp) {
  592.  
  593. #ifdef STDSTDIO            /* (the code works without this) */
  594.     if (stio->ifp->_cnt > 0)    /* cheat a little, since */
  595.         return FALSE;        /* this is the most usual case */
  596. #endif
  597.  
  598.     ch = getc(stio->ifp);
  599.     if (ch != EOF) {
  600.         (void)ungetc(ch, stio->ifp);
  601.         return FALSE;
  602.     }
  603. #ifdef STDSTDIO
  604.     if (stio->ifp->_cnt < -1)
  605.         stio->ifp->_cnt = -1;
  606. #endif
  607.     if (!stab) {            /* not necessarily a real EOF yet? */
  608.         if (!nextargv(argvstab))    /* get another fp handy */
  609.         return TRUE;
  610.     }
  611.     else
  612.         return TRUE;        /* normal fp, definitely end of file */
  613.     }
  614.     return TRUE;
  615. }
  616.  
  617. long
  618. do_tell(stab)
  619. STAB *stab;
  620. {
  621.     register STIO *stio;
  622.  
  623.     if (!stab)
  624.     goto phooey;
  625.  
  626.     stio = stab_io(stab);
  627.     if (!stio || !stio->ifp)
  628.     goto phooey;
  629.  
  630.     if (feof(stio->ifp))
  631.     (void)fseek (stio->ifp, 0L, 2);        /* ultrix 1.2 workaround */
  632.  
  633.     return ftell(stio->ifp);
  634.  
  635. phooey:
  636.     if (dowarn)
  637.     warn("tell() on unopened file");
  638.     errno = EBADF;
  639.     return -1L;
  640. }
  641.  
  642. bool
  643. do_seek(stab, pos, whence)
  644. STAB *stab;
  645. long pos;
  646. int whence;
  647. {
  648.     register STIO *stio;
  649.  
  650.     if (!stab)
  651.     goto nuts;
  652.  
  653.     stio = stab_io(stab);
  654.     if (!stio || !stio->ifp)
  655.     goto nuts;
  656.  
  657.     if (feof(stio->ifp))
  658.     (void)fseek (stio->ifp, 0L, 2);        /* ultrix 1.2 workaround */
  659.  
  660.     return fseek(stio->ifp, pos, whence) >= 0;
  661.  
  662. nuts:
  663.     if (dowarn)
  664.     warn("seek() on unopened file");
  665.     errno = EBADF;
  666.     return FALSE;
  667. }
  668.  
  669. int
  670. do_ctl(optype,stab,func,argstr)
  671. int optype;
  672. STAB *stab;
  673. int func;
  674. STR *argstr;
  675. {
  676.     register STIO *stio;
  677.     register char *s;
  678.     int retval;
  679.  
  680.     if (!stab || !argstr || !(stio = stab_io(stab)) || !stio->ifp) {
  681.     errno = EBADF;    /* well, sort of... */
  682.     return -1;
  683.     }
  684.  
  685.     if (argstr->str_pok || !argstr->str_nok) {
  686.     if (!argstr->str_pok)
  687.         s = str_get(argstr);
  688.  
  689. #ifdef IOCPARM_MASK
  690. #ifndef IOCPARM_LEN
  691. #define IOCPARM_LEN(x)  (((x) >> 16) & IOCPARM_MASK)
  692. #endif
  693. #endif
  694. #ifdef IOCPARM_LEN
  695.     retval = IOCPARM_LEN(func);    /* on BSDish systes we're safe */
  696. #else
  697.     retval = 256;            /* otherwise guess at what's safe */
  698. #endif
  699.     if (argstr->str_cur < retval) {
  700.         Str_Grow(argstr,retval+1);
  701.         argstr->str_cur = retval;
  702.     }
  703.  
  704.     s = argstr->str_ptr;
  705.     s[argstr->str_cur] = 17;    /* a little sanity check here */
  706.     }
  707.     else {
  708.     retval = (int)str_gnum(argstr);
  709. #ifdef MSDOS
  710.     s = (char*)(long)retval;        /* ouch */
  711. #else
  712.     s = (char*)retval;        /* ouch */
  713. #endif
  714.     }
  715.  
  716. #ifndef lint
  717.     if (optype == O_IOCTL)
  718.     retval = ioctl(fileno(stio->ifp), func, s);
  719.     else
  720. #ifdef MSDOS
  721.     fatal("fcntl is not implemented");
  722. #else
  723. #ifdef HAS_FCNTL
  724.     retval = fcntl(fileno(stio->ifp), func, s);
  725. #else
  726.     fatal("fcntl is not implemented");
  727. #endif
  728. #endif
  729. #else /* lint */
  730.     retval = 0;
  731. #endif /* lint */
  732.  
  733.     if (argstr->str_pok) {
  734.     if (s[argstr->str_cur] != 17)
  735.         fatal("Return value overflowed string");
  736.     s[argstr->str_cur] = 0;        /* put our null back */
  737.     }
  738.     return retval;
  739. }
  740.  
  741. int
  742. do_stat(str,arg,gimme,arglast)
  743. STR *str;
  744. register ARG *arg;
  745. int gimme;
  746. int *arglast;
  747. {
  748.     register ARRAY *ary = stack;
  749.     register int sp = arglast[0] + 1;
  750.     int max = 13;
  751.  
  752.     if ((arg[1].arg_type & A_MASK) == A_WORD) {
  753.     tmpstab = arg[1].arg_ptr.arg_stab;
  754.     if (tmpstab != defstab) {
  755.         laststype = O_STAT;
  756.         statstab = tmpstab;
  757.         str_set(statname,"");
  758.         if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
  759.           fstat(fileno(stab_io(tmpstab)->ifp),&statcache) < 0) {
  760.         max = 0;
  761.         laststatval = -1;
  762.         }
  763.     }
  764.     else if (laststatval < 0)
  765.         max = 0;
  766.     }
  767.     else {
  768.     str_set(statname,str_get(ary->ary_array[sp]));
  769.     statstab = Nullstab;
  770. #ifdef HAS_LSTAT
  771.     laststype = arg->arg_type;
  772.     if (arg->arg_type == O_LSTAT)
  773.         laststatval = lstat(str_get(statname),&statcache);
  774.     else
  775. #endif
  776.         laststatval = stat(str_get(statname),&statcache);
  777.     if (laststatval < 0)
  778.         max = 0;
  779.     }
  780.  
  781.     if (gimme != G_ARRAY) {
  782.     if (max)
  783.         str_sset(str,&str_yes);
  784.     else
  785.         str_sset(str,&str_undef);
  786.     STABSET(str);
  787.     ary->ary_array[sp] = str;
  788.     return sp;
  789.     }
  790.     sp--;
  791.     if (max) {
  792. #ifndef lint
  793.     (void)astore(ary,++sp,
  794.       str_2mortal(str_nmake((double)statcache.st_dev)));
  795.     (void)astore(ary,++sp,
  796.       str_2mortal(str_nmake((double)statcache.st_ino)));
  797.     (void)astore(ary,++sp,
  798.       str_2mortal(str_nmake((double)statcache.st_mode)));
  799.     (void)astore(ary,++sp,
  800.       str_2mortal(str_nmake((double)statcache.st_nlink)));
  801.     (void)astore(ary,++sp,
  802.       str_2mortal(str_nmake((double)statcache.st_uid)));
  803.     (void)astore(ary,++sp,
  804.       str_2mortal(str_nmake((double)statcache.st_gid)));
  805.     (void)astore(ary,++sp,
  806.       str_2mortal(str_nmake((double)statcache.st_rdev)));
  807.     (void)astore(ary,++sp,
  808.       str_2mortal(str_nmake((double)statcache.st_size)));
  809.     (void)astore(ary,++sp,
  810.       str_2mortal(str_nmake((double)statcache.st_atime)));
  811.     (void)astore(ary,++sp,
  812.       str_2mortal(str_nmake((double)statcache.st_mtime)));
  813.     (void)astore(ary,++sp,
  814.       str_2mortal(str_nmake((double)statcache.st_ctime)));
  815. #ifdef STATBLOCKS
  816.     (void)astore(ary,++sp,
  817.       str_2mortal(str_nmake((double)statcache.st_blksize)));
  818.     (void)astore(ary,++sp,
  819.       str_2mortal(str_nmake((double)statcache.st_blocks)));
  820. #else
  821.     (void)astore(ary,++sp,
  822.       str_2mortal(str_make("",0)));
  823.     (void)astore(ary,++sp,
  824.       str_2mortal(str_make("",0)));
  825. #endif
  826. #ifdef sprite
  827.     (void)astore(ary,++sp,
  828.       str_2mortal(str_nmake((double)statcache.st_serverID)));
  829.     (void)astore(ary,++sp,
  830.       str_2mortal(str_nmake((double)statcache.st_version)));
  831.     (void)astore(ary,++sp,
  832.       str_2mortal(str_nmake((double)statcache.st_userType)));
  833.     (void)astore(ary,++sp,
  834.       str_2mortal(str_nmake((double)statcache.st_devServerID)));
  835. #endif
  836.  
  837. #else /* lint */
  838.     (void)astore(ary,++sp,str_nmake(0.0));
  839. #endif /* lint */
  840.     }
  841.     return sp;
  842. }
  843.  
  844. #if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE) && defined(F_FREESP)
  845.     /* code courtesy of William Kucharski */
  846. #define HAS_CHSIZE
  847.  
  848. int chsize(fd, length)
  849. int fd;            /* file descriptor */
  850. off_t length;        /* length to set file to */
  851. {
  852.     extern long lseek();
  853.     struct flock fl;
  854.     struct stat filebuf;
  855.  
  856.     if (fstat(fd, &filebuf) < 0)
  857.     return -1;
  858.  
  859.     if (filebuf.st_size < length) {
  860.  
  861.     /* extend file length */
  862.  
  863.     if ((lseek(fd, (length - 1), 0)) < 0)
  864.         return -1;
  865.  
  866.     /* write a "0" byte */
  867.  
  868.     if ((write(fd, "", 1)) != 1)
  869.         return -1;
  870.     }
  871.     else {
  872.     /* truncate length */
  873.  
  874.     fl.l_whence = 0;
  875.     fl.l_len = 0;
  876.     fl.l_start = length;
  877.     fl.l_type = F_WRLCK;    /* write lock on file space */
  878.  
  879.     /*
  880.     * This relies on the UNDOCUMENTED F_FREESP argument to
  881.     * fcntl(2), which truncates the file so that it ends at the
  882.     * position indicated by fl.l_start.
  883.     *
  884.     * Will minor miracles never cease?
  885.     */
  886.  
  887.     if (fcntl(fd, F_FREESP, &fl) < 0)
  888.         return -1;
  889.  
  890.     }
  891.  
  892.     return 0;
  893. }
  894. #endif /* F_FREESP */
  895.  
  896. int                    /*SUPPRESS 590*/
  897. do_truncate(str,arg,gimme,arglast)
  898. STR *str;
  899. register ARG *arg;
  900. int gimme;
  901. int *arglast;
  902. {
  903.     register ARRAY *ary = stack;
  904.     register int sp = arglast[0] + 1;
  905.     off_t len = (off_t)str_gnum(ary->ary_array[sp+1]);
  906.     int result = 1;
  907.     STAB *tmpstab;
  908.  
  909. #if defined(HAS_TRUNCATE) || defined(HAS_CHSIZE)
  910. #ifdef HAS_TRUNCATE
  911.     if ((arg[1].arg_type & A_MASK) == A_WORD) {
  912.     tmpstab = arg[1].arg_ptr.arg_stab;
  913.     if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
  914.       ftruncate(fileno(stab_io(tmpstab)->ifp), len) < 0)
  915.         result = 0;
  916.     }
  917.     else if (truncate(str_get(ary->ary_array[sp]), len) < 0)
  918.     result = 0;
  919. #else
  920.     if ((arg[1].arg_type & A_MASK) == A_WORD) {
  921.     tmpstab = arg[1].arg_ptr.arg_stab;
  922.     if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
  923.       chsize(fileno(stab_io(tmpstab)->ifp), len) < 0)
  924.         result = 0;
  925.     }
  926.     else {
  927.     int tmpfd;
  928.  
  929.     if ((tmpfd = open(str_get(ary->ary_array[sp]), 0)) < 0)
  930.         result = 0;
  931.     else {
  932.         if (chsize(tmpfd, len) < 0)
  933.         result = 0;
  934.         close(tmpfd);
  935.     }
  936.     }
  937. #endif
  938.  
  939.     if (result)
  940.     str_sset(str,&str_yes);
  941.     else
  942.     str_sset(str,&str_undef);
  943.     STABSET(str);
  944.     ary->ary_array[sp] = str;
  945.     return sp;
  946. #else
  947.     fatal("truncate not implemented");
  948. #endif
  949. }
  950.  
  951. int
  952. looks_like_number(str)
  953. STR *str;
  954. {
  955.     register char *s;
  956.     register char *send;
  957.  
  958.     if (!str->str_pok)
  959.     return TRUE;
  960.     s = str->str_ptr; 
  961.     send = s + str->str_cur;
  962.     while (isSPACE(*s))
  963.     s++;
  964.     if (s >= send)
  965.     return FALSE;
  966.     if (*s == '+' || *s == '-')
  967.     s++;
  968.     while (isDIGIT(*s))
  969.     s++;
  970.     if (s == send)
  971.     return TRUE;
  972.     if (*s == '.') 
  973.     s++;
  974.     else if (s == str->str_ptr)
  975.     return FALSE;
  976.     while (isDIGIT(*s))
  977.     s++;
  978.     if (s == send)
  979.     return TRUE;
  980.     if (*s == 'e' || *s == 'E') {
  981.     s++;
  982.     if (*s == '+' || *s == '-')
  983.         s++;
  984.     while (isDIGIT(*s))
  985.         s++;
  986.     }
  987.     while (isSPACE(*s))
  988.     s++;
  989.     if (s >= send)
  990.     return TRUE;
  991.     return FALSE;
  992. }
  993.  
  994. bool
  995. do_print(str,fp)
  996. register STR *str;
  997. FILE *fp;
  998. {
  999.     register char *tmps;
  1000.  
  1001.     if (!fp) {
  1002.     if (dowarn)
  1003.         warn("print to unopened file");
  1004.     errno = EBADF;
  1005.     return FALSE;
  1006.     }
  1007.     if (!str)
  1008.     return TRUE;
  1009.     if (ofmt &&
  1010.       ((str->str_nok && str->str_u.str_nval != 0.0)
  1011.        || (looks_like_number(str) && str_gnum(str) != 0.0) ) ) {
  1012.     fprintf(fp, ofmt, str->str_u.str_nval);
  1013.     return !ferror(fp);
  1014.     }
  1015.     else {
  1016.     tmps = str_get(str);
  1017.     if (*tmps == 'S' && tmps[1] == 't' && tmps[2] == 'B' && tmps[3] == '\0'
  1018.       && str->str_cur == sizeof(STBP) && strlen(tmps) < str->str_cur) {
  1019.         STR *tmpstr = str_mortal(&str_undef);
  1020.         stab_fullname(tmpstr,((STAB*)str));/* a stab value, be nice */
  1021.         str = tmpstr;
  1022.         tmps = str->str_ptr;
  1023.         putc('*',fp);
  1024.     }
  1025.     if (str->str_cur && (fwrite(tmps,1,str->str_cur,fp) == 0 || ferror(fp)))
  1026.         return FALSE;
  1027.     }
  1028.     return TRUE;
  1029. }
  1030.  
  1031. bool
  1032. do_aprint(arg,fp,arglast)
  1033. register ARG *arg;
  1034. register FILE *fp;
  1035. int *arglast;
  1036. {
  1037.     register STR **st = stack->ary_array;
  1038.     register int sp = arglast[1];
  1039.     register int retval;
  1040.     register int items = arglast[2] - sp;
  1041.  
  1042.     if (!fp) {
  1043.     if (dowarn)
  1044.         warn("print to unopened file");
  1045.     errno = EBADF;
  1046.     return FALSE;
  1047.     }
  1048.     st += ++sp;
  1049.     if (arg->arg_type == O_PRTF) {
  1050.     do_sprintf(arg->arg_ptr.arg_str,items,st);
  1051.     retval = do_print(arg->arg_ptr.arg_str,fp);
  1052.     }
  1053.     else {
  1054.     retval = (items <= 0);
  1055.     for (; items > 0; items--,st++) {
  1056.         if (retval && ofslen) {
  1057.         if (fwrite(ofs, 1, ofslen, fp) == 0 || ferror(fp)) {
  1058.             retval = FALSE;
  1059.             break;
  1060.         }
  1061.         }
  1062.         if (!(retval = do_print(*st, fp)))
  1063.         break;
  1064.     }
  1065.     if (retval && orslen)
  1066.         if (fwrite(ors, 1, orslen, fp) == 0 || ferror(fp))
  1067.         retval = FALSE;
  1068.     }
  1069.     return retval;
  1070. }
  1071.  
  1072. int
  1073. mystat(arg,str)
  1074. ARG *arg;
  1075. STR *str;
  1076. {
  1077.     STIO *stio;
  1078.  
  1079.     if (arg[1].arg_type & A_DONT) {
  1080.     stio = stab_io(arg[1].arg_ptr.arg_stab);
  1081.     if (stio && stio->ifp) {
  1082.         statstab = arg[1].arg_ptr.arg_stab;
  1083.         str_set(statname,"");
  1084.         laststype = O_STAT;
  1085.         return (laststatval = fstat(fileno(stio->ifp), &statcache));
  1086.     }
  1087.     else {
  1088.         if (arg[1].arg_ptr.arg_stab == defstab)
  1089.         return laststatval;
  1090.         if (dowarn)
  1091.         warn("Stat on unopened file <%s>",
  1092.           stab_name(arg[1].arg_ptr.arg_stab));
  1093.         statstab = Nullstab;
  1094.         str_set(statname,"");
  1095.         return (laststatval = -1);
  1096.     }
  1097.     }
  1098.     else {
  1099.     statstab = Nullstab;
  1100.     str_set(statname,str_get(str));
  1101.     laststype = O_STAT;
  1102.     return (laststatval = stat(str_get(str),&statcache));
  1103.     }
  1104. }
  1105.  
  1106. int
  1107. mylstat(arg,str)
  1108. ARG *arg;
  1109. STR *str;
  1110. {
  1111.     if (arg[1].arg_type & A_DONT) {
  1112.     if (arg[1].arg_ptr.arg_stab == defstab) {
  1113.         if (laststype != O_LSTAT)
  1114.         fatal("The stat preceding -l _ wasn't an lstat");
  1115.         return laststatval;
  1116.     }
  1117.     fatal("You can't use -l on a filehandle");
  1118.     }
  1119.  
  1120.     laststype = O_LSTAT;
  1121.     statstab = Nullstab;
  1122.     str_set(statname,str_get(str));
  1123. #ifdef HAS_LSTAT
  1124.     return (laststatval = lstat(str_get(str),&statcache));
  1125. #else
  1126.     return (laststatval = stat(str_get(str),&statcache));
  1127. #endif
  1128. }
  1129.  
  1130. STR *
  1131. do_fttext(arg,str)
  1132. register ARG *arg;
  1133. STR *str;
  1134. {
  1135.     int i;
  1136.     int len;
  1137.     int odd = 0;
  1138.     STDCHAR tbuf[512];
  1139.     register STDCHAR *s;
  1140.     register STIO *stio;
  1141.  
  1142.     if (arg[1].arg_type & A_DONT) {
  1143.     if (arg[1].arg_ptr.arg_stab == defstab) {
  1144.         if (statstab)
  1145.         stio = stab_io(statstab);
  1146.         else {
  1147.         str = statname;
  1148.         goto really_filename;
  1149.         }
  1150.     }
  1151.     else {
  1152.         statstab = arg[1].arg_ptr.arg_stab;
  1153.         str_set(statname,"");
  1154.         stio = stab_io(statstab);
  1155.     }
  1156.     if (stio && stio->ifp) {
  1157. #ifdef STDSTDIO
  1158.         fstat(fileno(stio->ifp),&statcache);
  1159.         if (S_ISDIR(statcache.st_mode))    /* handle NFS glitch */
  1160.         return arg->arg_type == O_FTTEXT ? &str_no : &str_yes;
  1161.         if (stio->ifp->_cnt <= 0) {
  1162.         i = getc(stio->ifp);
  1163.         if (i != EOF)
  1164.             (void)ungetc(i,stio->ifp);
  1165.         }
  1166.         if (stio->ifp->_cnt <= 0)    /* null file is anything */
  1167.         return &str_yes;
  1168.         len = stio->ifp->_cnt + (stio->ifp->_ptr - stio->ifp->_base);
  1169.         s = stio->ifp->_base;
  1170. #else
  1171.         fatal("-T and -B not implemented on filehandles");
  1172. #endif
  1173.     }
  1174.     else {
  1175.         if (dowarn)
  1176.         warn("Test on unopened file <%s>",
  1177.           stab_name(arg[1].arg_ptr.arg_stab));
  1178.         errno = EBADF;
  1179.         return &str_undef;
  1180.     }
  1181.     }
  1182.     else {
  1183.     statstab = Nullstab;
  1184.     str_set(statname,str_get(str));
  1185.       really_filename:
  1186.     i = open(str_get(str),0);
  1187.     if (i < 0)
  1188.         return &str_undef;
  1189.     fstat(i,&statcache);
  1190.     len = read(i,tbuf,512);
  1191.     (void)close(i);
  1192.     if (len <= 0) {
  1193.         if (S_ISDIR(statcache.st_mode) && arg->arg_type == O_FTTEXT)
  1194.         return &str_no;        /* special case NFS directories */
  1195.         return &str_yes;        /* null file is anything */
  1196.     }
  1197.     s = tbuf;
  1198.     }
  1199.  
  1200.     /* now scan s to look for textiness */
  1201.  
  1202.     for (i = 0; i < len; i++,s++) {
  1203.     if (!*s) {            /* null never allowed in text */
  1204.         odd += len;
  1205.         break;
  1206.     }
  1207.     else if (*s & 128)
  1208.         odd++;
  1209.     else if (*s < 32 &&
  1210.       *s != '\n' && *s != '\r' && *s != '\b' &&
  1211.       *s != '\t' && *s != '\f' && *s != 27)
  1212.         odd++;
  1213.     }
  1214.  
  1215.     if ((odd * 10 > len) == (arg->arg_type == O_FTTEXT)) /* allow 10% odd */
  1216.     return &str_no;
  1217.     else
  1218.     return &str_yes;
  1219. }
  1220.  
  1221. bool
  1222. do_aexec(really,arglast)
  1223. STR *really;
  1224. int *arglast;
  1225. {
  1226.     register STR **st = stack->ary_array;
  1227.     register int sp = arglast[1];
  1228.     register int items = arglast[2] - sp;
  1229.     register char **a;
  1230.     char **argv;
  1231.     char *tmps;
  1232.  
  1233.     if (items) {
  1234.     New(401,argv, items+1, char*);
  1235.     a = argv;
  1236.     for (st += ++sp; items > 0; items--,st++) {
  1237.         if (*st)
  1238.         *a++ = str_get(*st);
  1239.         else
  1240.         *a++ = "";
  1241.     }
  1242.     *a = Nullch;
  1243. #ifdef TAINT
  1244.     if (*argv[0] != '/')    /* will execvp use PATH? */
  1245.         taintenv();        /* testing IFS here is overkill, probably */
  1246. #endif
  1247.     if (really && *(tmps = str_get(really)))
  1248.         execvp(tmps,argv);
  1249.     else
  1250.         execvp(argv[0],argv);
  1251.     Safefree(argv);
  1252.     }
  1253.     return FALSE;
  1254. }
  1255.  
  1256. static char **Argv = Null(char **);
  1257. static char *Cmd = Nullch;
  1258.  
  1259. void
  1260. do_execfree()
  1261. {
  1262.     if (Argv) {
  1263.     Safefree(Argv);
  1264.     Argv = Null(char **);
  1265.     }
  1266.     if (Cmd) {
  1267.     Safefree(Cmd);
  1268.     Cmd = Nullch;
  1269.     }
  1270. }
  1271.  
  1272. bool
  1273. do_exec(cmd)
  1274. char *cmd;
  1275. {
  1276.     register char **a;
  1277.     register char *s;
  1278.     char flags[10];
  1279.  
  1280.     /* save an extra exec if possible */
  1281.  
  1282. #ifdef CSH
  1283.     if (strnEQ(cmd,cshname,cshlen) && strnEQ(cmd+cshlen," -c",3)) {
  1284.     strcpy(flags,"-c");
  1285.     s = cmd+cshlen+3;
  1286.     if (*s == 'f') {
  1287.         s++;
  1288.         strcat(flags,"f");
  1289.     }
  1290.     if (*s == ' ')
  1291.         s++;
  1292.     if (*s++ == '\'') {
  1293.         char *ncmd = s;
  1294.  
  1295.         while (*s)
  1296.         s++;
  1297.         if (s[-1] == '\n')
  1298.         *--s = '\0';
  1299.         if (s[-1] == '\'') {
  1300.         *--s = '\0';
  1301.         execl(cshname,"csh", flags,ncmd,(char*)0);
  1302.         *s = '\'';
  1303.         return FALSE;
  1304.         }
  1305.     }
  1306.     }
  1307. #endif /* CSH */
  1308.  
  1309.     /* see if there are shell metacharacters in it */
  1310.  
  1311.     /*SUPPRESS 530*/
  1312.     for (s = cmd; *s && isALPHA(*s); s++) ;    /* catch VAR=val gizmo */
  1313.     if (*s == '=')
  1314.     goto doshell;
  1315.     for (s = cmd; *s; s++) {
  1316.     if (*s != ' ' && !isALPHA(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) {
  1317.         if (*s == '\n' && !s[1]) {
  1318.         *s = '\0';
  1319.         break;
  1320.         }
  1321.       doshell:
  1322.         execl("/bin/sh","sh","-c",cmd,(char*)0);
  1323.         return FALSE;
  1324.     }
  1325.     }
  1326.     New(402,Argv, (s - cmd) / 2 + 2, char*);
  1327.     Cmd = nsavestr(cmd, s-cmd);
  1328.     a = Argv;
  1329.     for (s = Cmd; *s;) {
  1330.     while (*s && isSPACE(*s)) s++;
  1331.     if (*s)
  1332.         *(a++) = s;
  1333.     while (*s && !isSPACE(*s)) s++;
  1334.     if (*s)
  1335.         *s++ = '\0';
  1336.     }
  1337.     *a = Nullch;
  1338.     if (Argv[0]) {
  1339.     execvp(Argv[0],Argv);
  1340.     if (errno == ENOEXEC) {        /* for system V NIH syndrome */
  1341.         do_execfree();
  1342.         goto doshell;
  1343.     }
  1344.     }
  1345.     do_execfree();
  1346.     return FALSE;
  1347. }
  1348.  
  1349. #ifdef HAS_SOCKET
  1350. int
  1351. do_socket(stab, arglast)
  1352. STAB *stab;
  1353. int *arglast;
  1354. {
  1355.     register STR **st = stack->ary_array;
  1356.     register int sp = arglast[1];
  1357.     register STIO *stio;
  1358.     int domain, type, protocol, fd;
  1359.  
  1360.     if (!stab) {
  1361.     errno = EBADF;
  1362.     return FALSE;
  1363.     }
  1364.  
  1365.     stio = stab_io(stab);
  1366.     if (!stio)
  1367.     stio = stab_io(stab) = stio_new();
  1368.     else if (stio->ifp)
  1369.     do_close(stab,FALSE);
  1370.  
  1371.     domain = (int)str_gnum(st[++sp]);
  1372.     type = (int)str_gnum(st[++sp]);
  1373.     protocol = (int)str_gnum(st[++sp]);
  1374. #ifdef TAINT
  1375.     taintproper("Insecure dependency in socket");
  1376. #endif
  1377.     fd = socket(domain,type,protocol);
  1378.     if (fd < 0)
  1379.     return FALSE;
  1380.     stio->ifp = fdopen(fd, "r");    /* stdio gets confused about sockets */
  1381.     stio->ofp = fdopen(fd, "w");
  1382.     stio->type = 's';
  1383.     if (!stio->ifp || !stio->ofp) {
  1384.     if (stio->ifp) fclose(stio->ifp);
  1385.     if (stio->ofp) fclose(stio->ofp);
  1386.     if (!stio->ifp && !stio->ofp) close(fd);
  1387.     return FALSE;
  1388.     }
  1389.  
  1390.     return TRUE;
  1391. }
  1392.  
  1393. int
  1394. do_bind(stab, arglast)
  1395. STAB *stab;
  1396. int *arglast;
  1397. {
  1398.     register STR **st = stack->ary_array;
  1399.     register int sp = arglast[1];
  1400.     register STIO *stio;
  1401.     char *addr;
  1402.  
  1403.     if (!stab)
  1404.     goto nuts;
  1405.  
  1406.     stio = stab_io(stab);
  1407.     if (!stio || !stio->ifp)
  1408.     goto nuts;
  1409.  
  1410.     addr = str_get(st[++sp]);
  1411. #ifdef TAINT
  1412.     taintproper("Insecure dependency in bind");
  1413. #endif
  1414.     return bind(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
  1415.  
  1416. nuts:
  1417.     if (dowarn)
  1418.     warn("bind() on closed fd");
  1419.     errno = EBADF;
  1420.     return FALSE;
  1421.  
  1422. }
  1423.  
  1424. int
  1425. do_connect(stab, arglast)
  1426. STAB *stab;
  1427. int *arglast;
  1428. {
  1429.     register STR **st = stack->ary_array;
  1430.     register int sp = arglast[1];
  1431.     register STIO *stio;
  1432.     char *addr;
  1433.  
  1434.     if (!stab)
  1435.     goto nuts;
  1436.  
  1437.     stio = stab_io(stab);
  1438.     if (!stio || !stio->ifp)
  1439.     goto nuts;
  1440.  
  1441.     addr = str_get(st[++sp]);
  1442. #ifdef TAINT
  1443.     taintproper("Insecure dependency in connect");
  1444. #endif
  1445.     return connect(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
  1446.  
  1447. nuts:
  1448.     if (dowarn)
  1449.     warn("connect() on closed fd");
  1450.     errno = EBADF;
  1451.     return FALSE;
  1452.  
  1453. }
  1454.  
  1455. int
  1456. do_listen(stab, arglast)
  1457. STAB *stab;
  1458. int *arglast;
  1459. {
  1460.     register STR **st = stack->ary_array;
  1461.     register int sp = arglast[1];
  1462.     register STIO *stio;
  1463.     int backlog;
  1464.  
  1465.     if (!stab)
  1466.     goto nuts;
  1467.  
  1468.     stio = stab_io(stab);
  1469.     if (!stio || !stio->ifp)
  1470.     goto nuts;
  1471.  
  1472.     backlog = (int)str_gnum(st[++sp]);
  1473.     return listen(fileno(stio->ifp), backlog) >= 0;
  1474.  
  1475. nuts:
  1476.     if (dowarn)
  1477.     warn("listen() on closed fd");
  1478.     errno = EBADF;
  1479.     return FALSE;
  1480. }
  1481.  
  1482. void
  1483. do_accept(str, nstab, gstab)
  1484. STR *str;
  1485. STAB *nstab;
  1486. STAB *gstab;
  1487. {
  1488.     register STIO *nstio;
  1489.     register STIO *gstio;
  1490.     int len = sizeof buf;
  1491.     int fd;
  1492.  
  1493.     if (!nstab)
  1494.     goto badexit;
  1495.     if (!gstab)
  1496.     goto nuts;
  1497.  
  1498.     gstio = stab_io(gstab);
  1499.     nstio = stab_io(nstab);
  1500.  
  1501.     if (!gstio || !gstio->ifp)
  1502.     goto nuts;
  1503.     if (!nstio)
  1504.     nstio = stab_io(nstab) = stio_new();
  1505.     else if (nstio->ifp)
  1506.     do_close(nstab,FALSE);
  1507.  
  1508.     fd = accept(fileno(gstio->ifp),(struct sockaddr *)buf,&len);
  1509.     if (fd < 0)
  1510.     goto badexit;
  1511.     nstio->ifp = fdopen(fd, "r");
  1512.     nstio->ofp = fdopen(fd, "w");
  1513.     nstio->type = 's';
  1514.     if (!nstio->ifp || !nstio->ofp) {
  1515.     if (nstio->ifp) fclose(nstio->ifp);
  1516.     if (nstio->ofp) fclose(nstio->ofp);
  1517.     if (!nstio->ifp && !nstio->ofp) close(fd);
  1518.     goto badexit;
  1519.     }
  1520.  
  1521.     str_nset(str, buf, len);
  1522.     return;
  1523.  
  1524. nuts:
  1525.     if (dowarn)
  1526.     warn("accept() on closed fd");
  1527.     errno = EBADF;
  1528. badexit:
  1529.     str_sset(str,&str_undef);
  1530.     return;
  1531. }
  1532.  
  1533. int
  1534. do_shutdown(stab, arglast)
  1535. STAB *stab;
  1536. int *arglast;
  1537. {
  1538.     register STR **st = stack->ary_array;
  1539.     register int sp = arglast[1];
  1540.     register STIO *stio;
  1541.     int how;
  1542.  
  1543.     if (!stab)
  1544.     goto nuts;
  1545.  
  1546.     stio = stab_io(stab);
  1547.     if (!stio || !stio->ifp)
  1548.     goto nuts;
  1549.  
  1550.     how = (int)str_gnum(st[++sp]);
  1551.     return shutdown(fileno(stio->ifp), how) >= 0;
  1552.  
  1553. nuts:
  1554.     if (dowarn)
  1555.     warn("shutdown() on closed fd");
  1556.     errno = EBADF;
  1557.     return FALSE;
  1558.  
  1559. }
  1560.  
  1561. int
  1562. do_sopt(optype, stab, arglast)
  1563. int optype;
  1564. STAB *stab;
  1565. int *arglast;
  1566. {
  1567.     register STR **st = stack->ary_array;
  1568.     register int sp = arglast[1];
  1569.     register STIO *stio;
  1570.     int fd;
  1571.     int lvl;
  1572.     int optname;
  1573.  
  1574.     if (!stab)
  1575.     goto nuts;
  1576.  
  1577.     stio = stab_io(stab);
  1578.     if (!stio || !stio->ifp)
  1579.     goto nuts;
  1580.  
  1581.     fd = fileno(stio->ifp);
  1582.     lvl = (int)str_gnum(st[sp+1]);
  1583.     optname = (int)str_gnum(st[sp+2]);
  1584.     switch (optype) {
  1585.     case O_GSOCKOPT:
  1586.     st[sp] = str_2mortal(Str_new(22,257));
  1587.     st[sp]->str_cur = 256;
  1588.     st[sp]->str_pok = 1;
  1589.     if (getsockopt(fd, lvl, optname, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
  1590.         goto nuts;
  1591.     break;
  1592.     case O_SSOCKOPT:
  1593.     st[sp] = st[sp+3];
  1594.     if (setsockopt(fd, lvl, optname, st[sp]->str_ptr, st[sp]->str_cur) < 0)
  1595.         goto nuts;
  1596.     st[sp] = &str_yes;
  1597.     break;
  1598.     }
  1599.     
  1600.     return sp;
  1601.  
  1602. nuts:
  1603.     if (dowarn)
  1604.     warn("[gs]etsockopt() on closed fd");
  1605.     st[sp] = &str_undef;
  1606.     errno = EBADF;
  1607.     return sp;
  1608.  
  1609. }
  1610.  
  1611. int
  1612. do_getsockname(optype, stab, arglast)
  1613. int optype;
  1614. STAB *stab;
  1615. int *arglast;
  1616. {
  1617.     register STR **st = stack->ary_array;
  1618.     register int sp = arglast[1];
  1619.     register STIO *stio;
  1620.     int fd;
  1621.  
  1622.     if (!stab)
  1623.     goto nuts;
  1624.  
  1625.     stio = stab_io(stab);
  1626.     if (!stio || !stio->ifp)
  1627.     goto nuts;
  1628.  
  1629.     st[sp] = str_2mortal(Str_new(22,257));
  1630.     st[sp]->str_cur = 256;
  1631.     st[sp]->str_pok = 1;
  1632.     fd = fileno(stio->ifp);
  1633.     switch (optype) {
  1634.     case O_GETSOCKNAME:
  1635.     if (getsockname(fd, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
  1636.         goto nuts2;
  1637.     break;
  1638.     case O_GETPEERNAME:
  1639.     if (getpeername(fd, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
  1640.         goto nuts2;
  1641.     break;
  1642.     }
  1643.     
  1644.     return sp;
  1645.  
  1646. nuts:
  1647.     if (dowarn)
  1648.     warn("get{sock,peer}name() on closed fd");
  1649.     errno = EBADF;
  1650. nuts2:
  1651.     st[sp] = &str_undef;
  1652.     return sp;
  1653.  
  1654. }
  1655.  
  1656. int
  1657. do_ghent(which,gimme,arglast)
  1658. int which;
  1659. int gimme;
  1660. int *arglast;
  1661. {
  1662.     register ARRAY *ary = stack;
  1663.     register int sp = arglast[0];
  1664.     register char **elem;
  1665.     register STR *str;
  1666.     struct hostent *gethostbyname();
  1667.     struct hostent *gethostbyaddr();
  1668. #ifdef HAS_GETHOSTENT
  1669.     struct hostent *gethostent();
  1670. #endif
  1671.     struct hostent *hent;
  1672.     unsigned long len;
  1673.  
  1674.     if (gimme != G_ARRAY) {
  1675.     astore(ary, ++sp, str_mortal(&str_undef));
  1676.     return sp;
  1677.     }
  1678.  
  1679.     if (which == O_GHBYNAME) {
  1680.     char *name = str_get(ary->ary_array[sp+1]);
  1681.  
  1682.     hent = gethostbyname(name);
  1683.     }
  1684.     else if (which == O_GHBYADDR) {
  1685.     STR *addrstr = ary->ary_array[sp+1];
  1686.     int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
  1687.     char *addr = str_get(addrstr);
  1688.  
  1689.     hent = gethostbyaddr(addr,addrstr->str_cur,addrtype);
  1690.     }
  1691.     else
  1692. #ifdef HAS_GETHOSTENT
  1693.     hent = gethostent();
  1694. #else
  1695.     fatal("gethostent not implemented");
  1696. #endif
  1697.     if (hent) {
  1698. #ifndef lint
  1699.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1700.     str_set(str, hent->h_name);
  1701.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1702.     for (elem = hent->h_aliases; *elem; elem++) {
  1703.         str_cat(str, *elem);
  1704.         if (elem[1])
  1705.         str_ncat(str," ",1);
  1706.     }
  1707.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1708.     str_numset(str, (double)hent->h_addrtype);
  1709.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1710.     len = hent->h_length;
  1711.     str_numset(str, (double)len);
  1712. #ifdef h_addr
  1713.     for (elem = hent->h_addr_list; *elem; elem++) {
  1714.         (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1715.         str_nset(str, *elem, len);
  1716.     }
  1717. #else
  1718.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1719.     str_nset(str, hent->h_addr, len);
  1720. #endif /* h_addr */
  1721. #else /* lint */
  1722.     elem = Nullch;
  1723.     elem = elem;
  1724.     (void)astore(ary, ++sp, str_mortal(&str_no));
  1725. #endif /* lint */
  1726.     }
  1727.  
  1728.     return sp;
  1729. }
  1730.  
  1731. int
  1732. do_gnent(which,gimme,arglast)
  1733. int which;
  1734. int gimme;
  1735. int *arglast;
  1736. {
  1737.     register ARRAY *ary = stack;
  1738.     register int sp = arglast[0];
  1739.     register char **elem;
  1740.     register STR *str;
  1741.     struct netent *getnetbyname();
  1742.     struct netent *getnetbyaddr();
  1743.     struct netent *getnetent();
  1744.     struct netent *nent;
  1745.  
  1746.     if (gimme != G_ARRAY) {
  1747.     astore(ary, ++sp, str_mortal(&str_undef));
  1748.     return sp;
  1749.     }
  1750.  
  1751.     if (which == O_GNBYNAME) {
  1752.     char *name = str_get(ary->ary_array[sp+1]);
  1753.  
  1754.     nent = getnetbyname(name);
  1755.     }
  1756.     else if (which == O_GNBYADDR) {
  1757.     unsigned long addr = U_L(str_gnum(ary->ary_array[sp+1]));
  1758.     int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
  1759.  
  1760.     nent = getnetbyaddr((long)addr,addrtype);
  1761.     }
  1762.     else
  1763.     nent = getnetent();
  1764.  
  1765.     if (nent) {
  1766. #ifndef lint
  1767.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1768.     str_set(str, nent->n_name);
  1769.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1770.     for (elem = nent->n_aliases; *elem; elem++) {
  1771.         str_cat(str, *elem);
  1772.         if (elem[1])
  1773.         str_ncat(str," ",1);
  1774.     }
  1775.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1776.     str_numset(str, (double)nent->n_addrtype);
  1777.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1778.     str_numset(str, (double)nent->n_net);
  1779. #else /* lint */
  1780.     elem = Nullch;
  1781.     elem = elem;
  1782.     (void)astore(ary, ++sp, str_mortal(&str_no));
  1783. #endif /* lint */
  1784.     }
  1785.  
  1786.     return sp;
  1787. }
  1788.  
  1789. int
  1790. do_gpent(which,gimme,arglast)
  1791. int which;
  1792. int gimme;
  1793. int *arglast;
  1794. {
  1795.     register ARRAY *ary = stack;
  1796.     register int sp = arglast[0];
  1797.     register char **elem;
  1798.     register STR *str;
  1799.     struct protoent *getprotobyname();
  1800.     struct protoent *getprotobynumber();
  1801.     struct protoent *getprotoent();
  1802.     struct protoent *pent;
  1803.  
  1804.     if (gimme != G_ARRAY) {
  1805.     astore(ary, ++sp, str_mortal(&str_undef));
  1806.     return sp;
  1807.     }
  1808.  
  1809.     if (which == O_GPBYNAME) {
  1810.     char *name = str_get(ary->ary_array[sp+1]);
  1811.  
  1812.     pent = getprotobyname(name);
  1813.     }
  1814.     else if (which == O_GPBYNUMBER) {
  1815.     int proto = (int)str_gnum(ary->ary_array[sp+1]);
  1816.  
  1817.     pent = getprotobynumber(proto);
  1818.     }
  1819.     else
  1820.     pent = getprotoent();
  1821.  
  1822.     if (pent) {
  1823. #ifndef lint
  1824.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1825.     str_set(str, pent->p_name);
  1826.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1827.     for (elem = pent->p_aliases; *elem; elem++) {
  1828.         str_cat(str, *elem);
  1829.         if (elem[1])
  1830.         str_ncat(str," ",1);
  1831.     }
  1832.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1833.     str_numset(str, (double)pent->p_proto);
  1834. #else /* lint */
  1835.     elem = Nullch;
  1836.     elem = elem;
  1837.     (void)astore(ary, ++sp, str_mortal(&str_no));
  1838. #endif /* lint */
  1839.     }
  1840.  
  1841.     return sp;
  1842. }
  1843.  
  1844. int
  1845. do_gsent(which,gimme,arglast)
  1846. int which;
  1847. int gimme;
  1848. int *arglast;
  1849. {
  1850.     register ARRAY *ary = stack;
  1851.     register int sp = arglast[0];
  1852.     register char **elem;
  1853.     register STR *str;
  1854.     struct servent *getservbyname();
  1855.     struct servent *getservbynumber();
  1856.     struct servent *getservent();
  1857.     struct servent *sent;
  1858.  
  1859.     if (gimme != G_ARRAY) {
  1860.     astore(ary, ++sp, str_mortal(&str_undef));
  1861.     return sp;
  1862.     }
  1863.  
  1864.     if (which == O_GSBYNAME) {
  1865.     char *name = str_get(ary->ary_array[sp+1]);
  1866.     char *proto = str_get(ary->ary_array[sp+2]);
  1867.  
  1868.     if (proto && !*proto)
  1869.         proto = Nullch;
  1870.  
  1871.     sent = getservbyname(name,proto);
  1872.     }
  1873.     else if (which == O_GSBYPORT) {
  1874.     int port = (int)str_gnum(ary->ary_array[sp+1]);
  1875.     char *proto = str_get(ary->ary_array[sp+2]);
  1876.  
  1877.     sent = getservbyport(port,proto);
  1878.     }
  1879.     else
  1880.     sent = getservent();
  1881.     if (sent) {
  1882. #ifndef lint
  1883.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1884.     str_set(str, sent->s_name);
  1885.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1886.     for (elem = sent->s_aliases; *elem; elem++) {
  1887.         str_cat(str, *elem);
  1888.         if (elem[1])
  1889.         str_ncat(str," ",1);
  1890.     }
  1891.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1892. #ifdef HAS_NTOHS
  1893.     str_numset(str, (double)ntohs(sent->s_port));
  1894. #else
  1895.     str_numset(str, (double)(sent->s_port));
  1896. #endif
  1897.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1898.     str_set(str, sent->s_proto);
  1899. #else /* lint */
  1900.     elem = Nullch;
  1901.     elem = elem;
  1902.     (void)astore(ary, ++sp, str_mortal(&str_no));
  1903. #endif /* lint */
  1904.     }
  1905.  
  1906.     return sp;
  1907. }
  1908.  
  1909. #endif /* HAS_SOCKET */
  1910.  
  1911. #ifdef HAS_SELECT
  1912. int
  1913. do_select(gimme,arglast)
  1914. int gimme;
  1915. int *arglast;
  1916. {
  1917.     register STR **st = stack->ary_array;
  1918.     register int sp = arglast[0];
  1919.     register int i;
  1920.     register int j;
  1921.     register char *s;
  1922.     register STR *str;
  1923.     double value;
  1924.     int maxlen = 0;
  1925.     int nfound;
  1926.     struct timeval timebuf;
  1927.     struct timeval *tbuf = &timebuf;
  1928.     int growsize;
  1929. #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
  1930.     int masksize;
  1931.     int offset;
  1932.     char *fd_sets[4];
  1933.     int k;
  1934.  
  1935. #if BYTEORDER & 0xf0000
  1936. #define ORDERBYTE (0x88888888 - BYTEORDER)
  1937. #else
  1938. #define ORDERBYTE (0x4444 - BYTEORDER)
  1939. #endif
  1940.  
  1941. #endif
  1942.  
  1943.     for (i = 1; i <= 3; i++) {
  1944.     j = st[sp+i]->str_cur;
  1945.     if (maxlen < j)
  1946.         maxlen = j;
  1947.     }
  1948.  
  1949. #if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
  1950.     growsize = maxlen;        /* little endians can use vecs directly */
  1951. #else
  1952. #ifdef NFDBITS
  1953.  
  1954. #ifndef NBBY
  1955. #define NBBY 8
  1956. #endif
  1957.  
  1958.     masksize = NFDBITS / NBBY;
  1959. #else
  1960.     masksize = sizeof(long);    /* documented int, everyone seems to use long */
  1961. #endif
  1962.     growsize = maxlen + (masksize - (maxlen % masksize));
  1963.     Zero(&fd_sets[0], 4, char*);
  1964. #endif
  1965.  
  1966.     for (i = 1; i <= 3; i++) {
  1967.     str = st[sp+i];
  1968.     j = str->str_len;
  1969.     if (j < growsize) {
  1970.         if (str->str_pok) {
  1971.         Str_Grow(str,growsize);
  1972.         s = str_get(str) + j;
  1973.         while (++j <= growsize) {
  1974.             *s++ = '\0';
  1975.         }
  1976.         }
  1977.         else if (str->str_ptr) {
  1978.         Safefree(str->str_ptr);
  1979.         str->str_ptr = Nullch;
  1980.         }
  1981.     }
  1982. #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
  1983.     s = str->str_ptr;
  1984.     if (s) {
  1985.         New(403, fd_sets[i], growsize, char);
  1986.         for (offset = 0; offset < growsize; offset += masksize) {
  1987.         for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
  1988.             fd_sets[i][j+offset] = s[(k % masksize) + offset];
  1989.         }
  1990.     }
  1991. #endif
  1992.     }
  1993.     str = st[sp+4];
  1994.     if (str->str_nok || str->str_pok) {
  1995.     value = str_gnum(str);
  1996.     if (value < 0.0)
  1997.         value = 0.0;
  1998.     timebuf.tv_sec = (long)value;
  1999.     value -= (double)timebuf.tv_sec;
  2000.     timebuf.tv_usec = (long)(value * 1000000.0);
  2001.     }
  2002.     else
  2003.     tbuf = Null(struct timeval*);
  2004.  
  2005. #if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
  2006.     nfound = select(
  2007.     maxlen * 8,
  2008.     st[sp+1]->str_ptr,
  2009.     st[sp+2]->str_ptr,
  2010.     st[sp+3]->str_ptr,
  2011.     tbuf);
  2012. #else
  2013.     nfound = select(
  2014.     maxlen * 8,
  2015.     fd_sets[1],
  2016.     fd_sets[2],
  2017.     fd_sets[3],
  2018.     tbuf);
  2019.     for (i = 1; i <= 3; i++) {
  2020.     if (fd_sets[i]) {
  2021.         str = st[sp+i];
  2022.         s = str->str_ptr;
  2023.         for (offset = 0; offset < growsize; offset += masksize) {
  2024.         for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
  2025.             s[(k % masksize) + offset] = fd_sets[i][j+offset];
  2026.         }
  2027.     }
  2028.     }
  2029. #endif
  2030.  
  2031.     st[++sp] = str_mortal(&str_no);
  2032.     str_numset(st[sp], (double)nfound);
  2033.     if (gimme == G_ARRAY && tbuf) {
  2034.     value = (double)(timebuf.tv_sec) +
  2035.         (double)(timebuf.tv_usec) / 1000000.0;
  2036.     st[++sp] = str_mortal(&str_no);
  2037.     str_numset(st[sp], value);
  2038.     }
  2039.     return sp;
  2040. }
  2041. #endif /* SELECT */
  2042.  
  2043. #ifdef HAS_SOCKET
  2044. int
  2045. do_spair(stab1, stab2, arglast)
  2046. STAB *stab1;
  2047. STAB *stab2;
  2048. int *arglast;
  2049. {
  2050.     register STR **st = stack->ary_array;
  2051.     register int sp = arglast[2];
  2052.     register STIO *stio1;
  2053.     register STIO *stio2;
  2054.     int domain, type, protocol, fd[2];
  2055.  
  2056.     if (!stab1 || !stab2)
  2057.     return FALSE;
  2058.  
  2059.     stio1 = stab_io(stab1);
  2060.     stio2 = stab_io(stab2);
  2061.     if (!stio1)
  2062.     stio1 = stab_io(stab1) = stio_new();
  2063.     else if (stio1->ifp)
  2064.     do_close(stab1,FALSE);
  2065.     if (!stio2)
  2066.     stio2 = stab_io(stab2) = stio_new();
  2067.     else if (stio2->ifp)
  2068.     do_close(stab2,FALSE);
  2069.  
  2070.     domain = (int)str_gnum(st[++sp]);
  2071.     type = (int)str_gnum(st[++sp]);
  2072.     protocol = (int)str_gnum(st[++sp]);
  2073. #ifdef TAINT
  2074.     taintproper("Insecure dependency in socketpair");
  2075. #endif
  2076. #ifdef HAS_SOCKETPAIR
  2077.     if (socketpair(domain,type,protocol,fd) < 0)
  2078.     return FALSE;
  2079. #else
  2080.     fatal("Socketpair unimplemented");
  2081. #endif
  2082.     stio1->ifp = fdopen(fd[0], "r");
  2083.     stio1->ofp = fdopen(fd[0], "w");
  2084.     stio1->type = 's';
  2085.     stio2->ifp = fdopen(fd[1], "r");
  2086.     stio2->ofp = fdopen(fd[1], "w");
  2087.     stio2->type = 's';
  2088.     if (!stio1->ifp || !stio1->ofp || !stio2->ifp || !stio2->ofp) {
  2089.     if (stio1->ifp) fclose(stio1->ifp);
  2090.     if (stio1->ofp) fclose(stio1->ofp);
  2091.     if (!stio1->ifp && !stio1->ofp) close(fd[0]);
  2092.     if (stio2->ifp) fclose(stio2->ifp);
  2093.     if (stio2->ofp) fclose(stio2->ofp);
  2094.     if (!stio2->ifp && !stio2->ofp) close(fd[1]);
  2095.     return FALSE;
  2096.     }
  2097.  
  2098.     return TRUE;
  2099. }
  2100.  
  2101. #endif /* HAS_SOCKET */
  2102.  
  2103. int
  2104. do_gpwent(which,gimme,arglast)
  2105. int which;
  2106. int gimme;
  2107. int *arglast;
  2108. {
  2109. #ifdef I_PWD
  2110.     register ARRAY *ary = stack;
  2111.     register int sp = arglast[0];
  2112.     register STR *str;
  2113.     struct passwd *getpwnam();
  2114.     struct passwd *getpwuid();
  2115.     struct passwd *getpwent();
  2116.     struct passwd *pwent;
  2117.  
  2118.     if (gimme != G_ARRAY) {
  2119.     astore(ary, ++sp, str_mortal(&str_undef));
  2120.     return sp;
  2121.     }
  2122.  
  2123.     if (which == O_GPWNAM) {
  2124.     char *name = str_get(ary->ary_array[sp+1]);
  2125.  
  2126.     pwent = getpwnam(name);
  2127.     }
  2128.     else if (which == O_GPWUID) {
  2129.     int uid = (int)str_gnum(ary->ary_array[sp+1]);
  2130.  
  2131.     pwent = getpwuid(uid);
  2132.     }
  2133.     else
  2134.     pwent = getpwent();
  2135.  
  2136.     if (pwent) {
  2137.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2138.     str_set(str, pwent->pw_name);
  2139.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2140.     str_set(str, pwent->pw_passwd);
  2141.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2142.     str_numset(str, (double)pwent->pw_uid);
  2143.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2144.     str_numset(str, (double)pwent->pw_gid);
  2145.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2146. #ifdef PWCHANGE
  2147.     str_numset(str, (double)pwent->pw_change);
  2148. #else
  2149. #ifdef PWQUOTA
  2150.     str_numset(str, (double)pwent->pw_quota);
  2151. #else
  2152. #ifdef PWAGE
  2153.     str_set(str, pwent->pw_age);
  2154. #endif
  2155. #endif
  2156. #endif
  2157.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2158. #ifdef PWCLASS
  2159.     str_set(str,pwent->pw_class);
  2160. #else
  2161. #ifdef PWCOMMENT
  2162.     str_set(str, pwent->pw_comment);
  2163. #endif
  2164. #endif
  2165.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2166.     str_set(str, pwent->pw_gecos);
  2167.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2168.     str_set(str, pwent->pw_dir);
  2169.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2170.     str_set(str, pwent->pw_shell);
  2171. #ifdef PWEXPIRE
  2172.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2173.     str_numset(str, (double)pwent->pw_expire);
  2174. #endif
  2175.     }
  2176.  
  2177.     return sp;
  2178. #else
  2179.     fatal("password routines not implemented");
  2180. #endif
  2181. }
  2182.  
  2183. int
  2184. do_ggrent(which,gimme,arglast)
  2185. int which;
  2186. int gimme;
  2187. int *arglast;
  2188. {
  2189. #ifdef I_GRP
  2190.     register ARRAY *ary = stack;
  2191.     register int sp = arglast[0];
  2192.     register char **elem;
  2193.     register STR *str;
  2194.     struct group *getgrnam();
  2195.     struct group *getgrgid();
  2196.     struct group *getgrent();
  2197.     struct group *grent;
  2198.  
  2199.     if (gimme != G_ARRAY) {
  2200.     astore(ary, ++sp, str_mortal(&str_undef));
  2201.     return sp;
  2202.     }
  2203.  
  2204.     if (which == O_GGRNAM) {
  2205.     char *name = str_get(ary->ary_array[sp+1]);
  2206.  
  2207.     grent = getgrnam(name);
  2208.     }
  2209.     else if (which == O_GGRGID) {
  2210.     int gid = (int)str_gnum(ary->ary_array[sp+1]);
  2211.  
  2212.     grent = getgrgid(gid);
  2213.     }
  2214.     else
  2215.     grent = getgrent();
  2216.  
  2217.     if (grent) {
  2218.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2219.     str_set(str, grent->gr_name);
  2220.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2221.     str_set(str, grent->gr_passwd);
  2222.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2223.     str_numset(str, (double)grent->gr_gid);
  2224.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2225.     for (elem = grent->gr_mem; *elem; elem++) {
  2226.         str_cat(str, *elem);
  2227.         if (elem[1])
  2228.         str_ncat(str," ",1);
  2229.     }
  2230.     }
  2231.  
  2232.     return sp;
  2233. #else
  2234.     fatal("group routines not implemented");
  2235. #endif
  2236. }
  2237.  
  2238. int
  2239. do_dirop(optype,stab,gimme,arglast)
  2240. int optype;
  2241. STAB *stab;
  2242. int gimme;
  2243. int *arglast;
  2244. {
  2245. #if defined(DIRENT) && defined(HAS_READDIR)
  2246.     register ARRAY *ary = stack;
  2247.     register STR **st = ary->ary_array;
  2248.     register int sp = arglast[1];
  2249.     register STIO *stio;
  2250.     long along;
  2251. #ifndef telldir
  2252.     long telldir();
  2253. #endif
  2254. #ifndef apollo
  2255.     struct DIRENT *readdir();
  2256. #endif
  2257.     register struct DIRENT *dp;
  2258.  
  2259.     if (!stab)
  2260.     goto nope;
  2261.     if (!(stio = stab_io(stab)))
  2262.     stio = stab_io(stab) = stio_new();
  2263.     if (!stio->dirp && optype != O_OPEN_DIR)
  2264.     goto nope;
  2265.     st[sp] = &str_yes;
  2266.     switch (optype) {
  2267.     case O_OPEN_DIR:
  2268.     if (stio->dirp)
  2269.         closedir(stio->dirp);
  2270.     if (!(stio->dirp = opendir(str_get(st[sp+1]))))
  2271.         goto nope;
  2272.     break;
  2273.     case O_READDIR:
  2274.     if (gimme == G_ARRAY) {
  2275.         --sp;
  2276.         /*SUPPRESS 560*/
  2277.         while (dp = readdir(stio->dirp)) {
  2278. #ifdef DIRNAMLEN
  2279.         (void)astore(ary,++sp,
  2280.           str_2mortal(str_make(dp->d_name,dp->d_namlen)));
  2281. #else
  2282.         (void)astore(ary,++sp,
  2283.           str_2mortal(str_make(dp->d_name,0)));
  2284. #endif
  2285.         }
  2286.     }
  2287.     else {
  2288.         if (!(dp = readdir(stio->dirp)))
  2289.         goto nope;
  2290.         st[sp] = str_mortal(&str_undef);
  2291. #ifdef DIRNAMLEN
  2292.         str_nset(st[sp], dp->d_name, dp->d_namlen);
  2293. #else
  2294.         str_set(st[sp], dp->d_name);
  2295. #endif
  2296.     }
  2297.     break;
  2298. #if MACH
  2299.     case O_TELLDIR:
  2300.     case O_SEEKDIR:
  2301.         goto nope;
  2302. #else
  2303.     case O_TELLDIR:
  2304.     st[sp] = str_mortal(&str_undef);
  2305.     str_numset(st[sp], (double)telldir(stio->dirp));
  2306.     break;
  2307.     case O_SEEKDIR:
  2308.     st[sp] = str_mortal(&str_undef);
  2309.     along = (long)str_gnum(st[sp+1]);
  2310.     (void)seekdir(stio->dirp,along);
  2311.     break;
  2312. #endif
  2313.     case O_REWINDDIR:
  2314.     st[sp] = str_mortal(&str_undef);
  2315.     (void)rewinddir(stio->dirp);
  2316.     break;
  2317.     case O_CLOSEDIR:
  2318.     st[sp] = str_mortal(&str_undef);
  2319.     (void)closedir(stio->dirp);
  2320.     stio->dirp = 0;
  2321.     break;
  2322.     }
  2323.     return sp;
  2324.  
  2325. nope:
  2326.     st[sp] = &str_undef;
  2327.     if (!errno)
  2328.     errno = EBADF;
  2329.     return sp;
  2330.  
  2331. #else
  2332.     fatal("Unimplemented directory operation");
  2333. #endif
  2334. }
  2335.  
  2336. apply(type,arglast)
  2337. int type;
  2338. int *arglast;
  2339. {
  2340.     register STR **st = stack->ary_array;
  2341.     register int sp = arglast[1];
  2342.     register int items = arglast[2] - sp;
  2343.     register int val;
  2344.     register int val2;
  2345.     register int tot = 0;
  2346.     char *s;
  2347.  
  2348. #ifdef TAINT
  2349.     for (st += ++sp; items--; st++)
  2350.     tainted |= (*st)->str_tainted;
  2351.     st = stack->ary_array;
  2352.     sp = arglast[1];
  2353.     items = arglast[2] - sp;
  2354. #endif
  2355.     switch (type) {
  2356.     case O_CHMOD:
  2357. #ifdef TAINT
  2358.     taintproper("Insecure dependency in chmod");
  2359. #endif
  2360.     if (--items > 0) {
  2361.         tot = items;
  2362.         val = (int)str_gnum(st[++sp]);
  2363.         while (items--) {
  2364.         if (chmod(str_get(st[++sp]),val))
  2365.             tot--;
  2366.         }
  2367.     }
  2368.     break;
  2369. #ifdef HAS_CHOWN
  2370.     case O_CHOWN:
  2371. #ifdef TAINT
  2372.     taintproper("Insecure dependency in chown");
  2373. #endif
  2374.     if (items > 2) {
  2375.         items -= 2;
  2376.         tot = items;
  2377.         val = (int)str_gnum(st[++sp]);
  2378.         val2 = (int)str_gnum(st[++sp]);
  2379.         while (items--) {
  2380.         if (chown(str_get(st[++sp]),val,val2))
  2381.             tot--;
  2382.         }
  2383.     }
  2384.     break;
  2385. #endif
  2386. #ifdef HAS_KILL
  2387.     case O_KILL:
  2388. #ifdef TAINT
  2389.     taintproper("Insecure dependency in kill");
  2390. #endif
  2391.     if (--items > 0) {
  2392.         tot = items;
  2393.         s = str_get(st[++sp]);
  2394.         if (isUPPER(*s)) {
  2395.         if (*s == 'S' && s[1] == 'I' && s[2] == 'G')
  2396.             s += 3;
  2397.         if (!(val = whichsig(s)))
  2398.             fatal("Unrecognized signal name \"%s\"",s);
  2399.         }
  2400.         else
  2401.         val = (int)str_gnum(st[sp]);
  2402.         if (val < 0) {
  2403.         val = -val;
  2404.         while (items--) {
  2405.             int proc = (int)str_gnum(st[++sp]);
  2406. #ifdef HAS_KILLPG
  2407.             if (killpg(proc,val))    /* BSD */
  2408. #else
  2409.             if (kill(-proc,val))    /* SYSV */
  2410. #endif
  2411.             tot--;
  2412.         }
  2413.         }
  2414.         else {
  2415.         while (items--) {
  2416.             if (kill((int)(str_gnum(st[++sp])),val))
  2417.             tot--;
  2418.         }
  2419.         }
  2420.     }
  2421.     break;
  2422. #endif
  2423.     case O_UNLINK:
  2424. #ifdef TAINT
  2425.     taintproper("Insecure dependency in unlink");
  2426. #endif
  2427.     tot = items;
  2428.     while (items--) {
  2429.         s = str_get(st[++sp]);
  2430.         if (euid || unsafe) {
  2431.         if (UNLINK(s))
  2432.             tot--;
  2433.         }
  2434.         else {    /* don't let root wipe out directories without -U */
  2435. #ifdef HAS_LSTAT
  2436.         if (lstat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
  2437. #else
  2438.         if (stat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
  2439. #endif
  2440.             tot--;
  2441.         else {
  2442.             if (UNLINK(s))
  2443.             tot--;
  2444.         }
  2445.         }
  2446.     }
  2447.     break;
  2448.     case O_UTIME:
  2449. #ifdef TAINT
  2450.     taintproper("Insecure dependency in utime");
  2451. #endif
  2452.     if (items > 2) {
  2453. #ifdef I_UTIME
  2454.         struct utimbuf utbuf;
  2455. #else
  2456.         struct {
  2457.         long    actime;
  2458.         long    modtime;
  2459.         } utbuf;
  2460. #endif
  2461.  
  2462.         Zero(&utbuf, sizeof utbuf, char);
  2463.         utbuf.actime = (long)str_gnum(st[++sp]);    /* time accessed */
  2464.         utbuf.modtime = (long)str_gnum(st[++sp]);    /* time modified */
  2465.         items -= 2;
  2466. #ifndef lint
  2467.         tot = items;
  2468.         while (items--) {
  2469.         if (utime(str_get(st[++sp]),&utbuf))
  2470.             tot--;
  2471.         }
  2472. #endif
  2473.     }
  2474.     else
  2475.         items = 0;
  2476.     break;
  2477.     }
  2478.     return tot;
  2479. }
  2480.  
  2481. /* Do the permissions allow some operation?  Assumes statcache already set. */
  2482.  
  2483. int
  2484. cando(bit, effective, statbufp)
  2485. int bit;
  2486. int effective;
  2487. register struct stat *statbufp;
  2488. {
  2489. #ifdef MSDOS
  2490.     /* [Comments and code from Len Reed]
  2491.      * MS-DOS "user" is similar to UNIX's "superuser," but can't write
  2492.      * to write-protected files.  The execute permission bit is set
  2493.      * by the Miscrosoft C library stat() function for the following:
  2494.      *        .exe files
  2495.      *        .com files
  2496.      *        .bat files
  2497.      *        directories
  2498.      * All files and directories are readable.
  2499.      * Directories and special files, e.g. "CON", cannot be
  2500.      * write-protected.
  2501.      * [Comment by Tom Dinger -- a directory can have the write-protect
  2502.      *        bit set in the file system, but DOS permits changes to
  2503.      *        the directory anyway.  In addition, all bets are off
  2504.      *        here for networked software, such as Novell and
  2505.      *        Sun's PC-NFS.]
  2506.      */
  2507.  
  2508.      return (bit & statbufp->st_mode) ? TRUE : FALSE;
  2509.  
  2510. #else /* ! MSDOS */
  2511.     if ((effective ? euid : uid) == 0) {    /* root is special */
  2512.     if (bit == S_IXUSR) {
  2513.         if (statbufp->st_mode & 0111 || S_ISDIR(statbufp->st_mode))
  2514.         return TRUE;
  2515.     }
  2516.     else
  2517.         return TRUE;        /* root reads and writes anything */
  2518.     return FALSE;
  2519.     }
  2520.     if (statbufp->st_uid == (effective ? euid : uid) ) {
  2521.     if (statbufp->st_mode & bit)
  2522.         return TRUE;    /* ok as "user" */
  2523.     }
  2524.     else if (ingroup((int)statbufp->st_gid,effective)) {
  2525.     if (statbufp->st_mode & bit >> 3)
  2526.         return TRUE;    /* ok as "group" */
  2527.     }
  2528.     else if (statbufp->st_mode & bit >> 6)
  2529.     return TRUE;    /* ok as "other" */
  2530.     return FALSE;
  2531. #endif /* ! MSDOS */
  2532. }
  2533.  
  2534. int
  2535. ingroup(testgid,effective)
  2536. int testgid;
  2537. int effective;
  2538. {
  2539.     if (testgid == (effective ? egid : gid))
  2540.     return TRUE;
  2541. #ifdef HAS_GETGROUPS
  2542. #ifndef NGROUPS
  2543. #define NGROUPS 32
  2544. #endif
  2545.     {
  2546.     GROUPSTYPE gary[NGROUPS];
  2547.     int anum;
  2548.  
  2549.     anum = getgroups(NGROUPS,gary);
  2550.     while (--anum >= 0)
  2551.         if (gary[anum] == testgid)
  2552.         return TRUE;
  2553.     }
  2554. #endif
  2555.     return FALSE;
  2556. }
  2557.  
  2558. #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
  2559.  
  2560. int
  2561. do_ipcget(optype, arglast)
  2562. int optype;
  2563. int *arglast;
  2564. {
  2565.     register STR **st = stack->ary_array;
  2566.     register int sp = arglast[0];
  2567.     key_t key;
  2568.     int n, flags;
  2569.  
  2570.     key = (key_t)str_gnum(st[++sp]);
  2571.     n = (optype == O_MSGGET) ? 0 : (int)str_gnum(st[++sp]);
  2572.     flags = (int)str_gnum(st[++sp]);
  2573.     errno = 0;
  2574.     switch (optype)
  2575.     {
  2576. #ifdef HAS_MSG
  2577.     case O_MSGGET:
  2578.     return msgget(key, flags);
  2579. #endif
  2580. #ifdef HAS_SEM
  2581.     case O_SEMGET:
  2582.     return semget(key, n, flags);
  2583. #endif
  2584. #ifdef HAS_SHM
  2585.     case O_SHMGET:
  2586.     return shmget(key, n, flags);
  2587. #endif
  2588. #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
  2589.     default:
  2590.     fatal("%s not implemented", opname[optype]);
  2591. #endif
  2592.     }
  2593.     return -1;            /* should never happen */
  2594. }
  2595.  
  2596. int
  2597. do_ipcctl(optype, arglast)
  2598. int optype;
  2599. int *arglast;
  2600. {
  2601.     register STR **st = stack->ary_array;
  2602.     register int sp = arglast[0];
  2603.     STR *astr;
  2604.     char *a;
  2605.     int id, n, cmd, infosize, getinfo, ret;
  2606.  
  2607.     id = (int)str_gnum(st[++sp]);
  2608.     n = (optype == O_SEMCTL) ? (int)str_gnum(st[++sp]) : 0;
  2609.     cmd = (int)str_gnum(st[++sp]);
  2610.     astr = st[++sp];
  2611.  
  2612.     infosize = 0;
  2613.     getinfo = (cmd == IPC_STAT);
  2614.  
  2615.     switch (optype)
  2616.     {
  2617. #ifdef HAS_MSG
  2618.     case O_MSGCTL:
  2619.     if (cmd == IPC_STAT || cmd == IPC_SET)
  2620.         infosize = sizeof(struct msqid_ds);
  2621.     break;
  2622. #endif
  2623. #ifdef HAS_SHM
  2624.     case O_SHMCTL:
  2625.     if (cmd == IPC_STAT || cmd == IPC_SET)
  2626.         infosize = sizeof(struct shmid_ds);
  2627.     break;
  2628. #endif
  2629. #ifdef HAS_SEM
  2630.     case O_SEMCTL:
  2631.     if (cmd == IPC_STAT || cmd == IPC_SET)
  2632.         infosize = sizeof(struct semid_ds);
  2633.     else if (cmd == GETALL || cmd == SETALL)
  2634.     {
  2635.         struct semid_ds semds;
  2636.         if (semctl(id, 0, IPC_STAT, &semds) == -1)
  2637.         return -1;
  2638.         getinfo = (cmd == GETALL);
  2639.         infosize = semds.sem_nsems * sizeof(short);
  2640.         /* "short" is technically wrong but much more portable
  2641.            than guessing about u_?short(_t)? */
  2642.     }
  2643.     break;
  2644. #endif
  2645. #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
  2646.     default:
  2647.     fatal("%s not implemented", opname[optype]);
  2648. #endif
  2649.     }
  2650.  
  2651.     if (infosize)
  2652.     {
  2653.     if (getinfo)
  2654.     {
  2655.         STR_GROW(astr, infosize+1);
  2656.         a = str_get(astr);
  2657.     }
  2658.     else
  2659.     {
  2660.         a = str_get(astr);
  2661.         if (astr->str_cur != infosize)
  2662.         {
  2663.         errno = EINVAL;
  2664.         return -1;
  2665.         }
  2666.     }
  2667.     }
  2668.     else
  2669.     {
  2670.     int i = (int)str_gnum(astr);
  2671.     a = (char *)i;        /* ouch */
  2672.     }
  2673.     errno = 0;
  2674.     switch (optype)
  2675.     {
  2676. #ifdef HAS_MSG
  2677.     case O_MSGCTL:
  2678.     ret = msgctl(id, cmd, a);
  2679.     break;
  2680. #endif
  2681. #ifdef HAS_SEM
  2682.     case O_SEMCTL:
  2683.     ret = semctl(id, n, cmd, a);
  2684.     break;
  2685. #endif
  2686. #ifdef HAS_SHM
  2687.     case O_SHMCTL:
  2688.     ret = shmctl(id, cmd, a);
  2689.     break;
  2690. #endif
  2691.     }
  2692.     if (getinfo && ret >= 0) {
  2693.     astr->str_cur = infosize;
  2694.     astr->str_ptr[infosize] = '\0';
  2695.     }
  2696.     return ret;
  2697. }
  2698.  
  2699. int
  2700. do_msgsnd(arglast)
  2701. int *arglast;
  2702. {
  2703. #ifdef HAS_MSG
  2704.     register STR **st = stack->ary_array;
  2705.     register int sp = arglast[0];
  2706.     STR *mstr;
  2707.     char *mbuf;
  2708.     int id, msize, flags;
  2709.  
  2710.     id = (int)str_gnum(st[++sp]);
  2711.     mstr = st[++sp];
  2712.     flags = (int)str_gnum(st[++sp]);
  2713.     mbuf = str_get(mstr);
  2714.     if ((msize = mstr->str_cur - sizeof(long)) < 0) {
  2715.     errno = EINVAL;
  2716.     return -1;
  2717.     }
  2718.     errno = 0;
  2719.     return msgsnd(id, mbuf, msize, flags);
  2720. #else
  2721.     fatal("msgsnd not implemented");
  2722. #endif
  2723. }
  2724.  
  2725. int
  2726. do_msgrcv(arglast)
  2727. int *arglast;
  2728. {
  2729. #ifdef HAS_MSG
  2730.     register STR **st = stack->ary_array;
  2731.     register int sp = arglast[0];
  2732.     STR *mstr;
  2733.     char *mbuf;
  2734.     long mtype;
  2735.     int id, msize, flags, ret;
  2736.  
  2737.     id = (int)str_gnum(st[++sp]);
  2738.     mstr = st[++sp];
  2739.     msize = (int)str_gnum(st[++sp]);
  2740.     mtype = (long)str_gnum(st[++sp]);
  2741.     flags = (int)str_gnum(st[++sp]);
  2742.     mbuf = str_get(mstr);
  2743.     if (mstr->str_cur < sizeof(long)+msize+1) {
  2744.     STR_GROW(mstr, sizeof(long)+msize+1);
  2745.     mbuf = str_get(mstr);
  2746.     }
  2747.     errno = 0;
  2748.     ret = msgrcv(id, mbuf, msize, mtype, flags);
  2749.     if (ret >= 0) {
  2750.     mstr->str_cur = sizeof(long)+ret;
  2751.     mstr->str_ptr[sizeof(long)+ret] = '\0';
  2752.     }
  2753.     return ret;
  2754. #else
  2755.     fatal("msgrcv not implemented");
  2756. #endif
  2757. }
  2758.  
  2759. int
  2760. do_semop(arglast)
  2761. int *arglast;
  2762. {
  2763. #ifdef HAS_SEM
  2764.     register STR **st = stack->ary_array;
  2765.     register int sp = arglast[0];
  2766.     STR *opstr;
  2767.     char *opbuf;
  2768.     int id, opsize;
  2769.  
  2770.     id = (int)str_gnum(st[++sp]);
  2771.     opstr = st[++sp];
  2772.     opbuf = str_get(opstr);
  2773.     opsize = opstr->str_cur;
  2774.     if (opsize < sizeof(struct sembuf)
  2775.     || (opsize % sizeof(struct sembuf)) != 0) {
  2776.     errno = EINVAL;
  2777.     return -1;
  2778.     }
  2779.     errno = 0;
  2780.     return semop(id, (struct sembuf *)opbuf, opsize/sizeof(struct sembuf));
  2781. #else
  2782.     fatal("semop not implemented");
  2783. #endif
  2784. }
  2785.  
  2786. int
  2787. do_shmio(optype, arglast)
  2788. int optype;
  2789. int *arglast;
  2790. {
  2791. #ifdef HAS_SHM
  2792.     register STR **st = stack->ary_array;
  2793.     register int sp = arglast[0];
  2794.     STR *mstr;
  2795.     char *mbuf, *shm;
  2796.     int id, mpos, msize;
  2797.     struct shmid_ds shmds;
  2798. #ifndef VOIDSHMAT
  2799.     extern char *shmat();
  2800. #endif
  2801.  
  2802.     id = (int)str_gnum(st[++sp]);
  2803.     mstr = st[++sp];
  2804.     mpos = (int)str_gnum(st[++sp]);
  2805.     msize = (int)str_gnum(st[++sp]);
  2806.     errno = 0;
  2807.     if (shmctl(id, IPC_STAT, &shmds) == -1)
  2808.     return -1;
  2809.     if (mpos < 0 || msize < 0 || mpos + msize > shmds.shm_segsz) {
  2810.     errno = EFAULT;        /* can't do as caller requested */
  2811.     return -1;
  2812.     }
  2813.     shm = (char*)shmat(id, (char*)NULL, (optype == O_SHMREAD) ? SHM_RDONLY : 0);
  2814.     if (shm == (char *)-1)    /* I hate System V IPC, I really do */
  2815.     return -1;
  2816.     mbuf = str_get(mstr);
  2817.     if (optype == O_SHMREAD) {
  2818.     if (mstr->str_cur < msize) {
  2819.         STR_GROW(mstr, msize+1);
  2820.         mbuf = str_get(mstr);
  2821.     }
  2822.     bcopy(shm + mpos, mbuf, msize);
  2823.     mstr->str_cur = msize;
  2824.     mstr->str_ptr[msize] = '\0';
  2825.     }
  2826.     else {
  2827.     int n;
  2828.  
  2829.     if ((n = mstr->str_cur) > msize)
  2830.         n = msize;
  2831.     bcopy(mbuf, shm + mpos, n);
  2832.     if (n < msize)
  2833.         bzero(shm + mpos + n, msize - n);
  2834.     }
  2835.     return shmdt(shm);
  2836. #else
  2837.     fatal("shm I/O not implemented");
  2838. #endif
  2839. }
  2840.  
  2841. #endif /* SYSV IPC */
  2842.